﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    public class GZipHelper
    {
        // Methods
        public static GZipResult Compress(string lpSourceFolder, string lpDestFolder, string zipFileName)
        {
            return Compress(lpSourceFolder, "*.*", SearchOption.AllDirectories, lpDestFolder, zipFileName, true);
        }

        public static GZipResult Compress(FileInfo[] files, string lpBaseFolder, string lpDestFolder, string zipFileName)
        {
            return Compress(files, lpBaseFolder, lpDestFolder, zipFileName, true);
        }

        public static GZipResult Compress(FileInfo[] files, string lpBaseFolder, string lpDestFolder, string zipFileName, bool deleteTempFile)
        {
            GZipResult result = new GZipResult();
            try
            {
                if (!lpDestFolder.EndsWith(@"\"))
                {
                    lpDestFolder = lpDestFolder + @"\";
                }
                if (!Directory.Exists(lpDestFolder))
                {
                    Directory.CreateDirectory(lpDestFolder);
                }
                string lpTempFile = lpDestFolder + zipFileName + ".tmp";
                string lpZipFile = lpDestFolder + zipFileName;
                result.TempFile = lpTempFile;
                result.ZipFile = lpZipFile;
                if ((files == null) || (files.Length <= 0))
                {
                    return result;
                }
                CreateTempFile(files, lpBaseFolder, lpTempFile, result);
                if (result.FileCount > 0)
                {
                    CreateZipFile(lpTempFile, lpZipFile, result);
                }
                if (deleteTempFile)
                {
                    File.Delete(lpTempFile);
                    result.TempFileDeleted = true;
                }
            }
            catch (Exception exception)
            {
                result.Errors = true;
                result.Message = exception.Message;
            }
            return result;
        }

        public static GZipResult Compress(FileInfo[] files, string[] folders, string baseFolder, string saveFolder, string zipFileName)
        {
            IList<FileInfo> source = new List<FileInfo>();
            if (files != null)
            {
                foreach (FileInfo info in files)
                {
                    source.Add(info);
                }
            }
            if (folders != null)
            {
                foreach (string str in folders)
                {
                    DirectoryInfo info2 = new DirectoryInfo(str);
                    foreach (FileInfo info3 in info2.GetFiles("*.*", SearchOption.AllDirectories))
                    {
                        source.Add(info3);
                    }
                }
            }
            return Compress(source.ToArray<FileInfo>(), baseFolder, saveFolder, zipFileName, true);
        }

        public static GZipResult Compress(string lpSourceFolder, string searchPattern, SearchOption searchOption, string lpDestFolder, string zipFileName, bool deleteTempFile)
        {
            DirectoryInfo info = new DirectoryInfo(lpSourceFolder);
            return Compress(info.GetFiles("*.*", searchOption), lpSourceFolder, lpDestFolder, zipFileName, deleteTempFile);
        }

        private static void CreateTempFile(FileInfo[] files, string lpBaseFolder, string lpTempFile, GZipResult result)
        {
            string s = null;
            string str2 = null;
            int index = 0;
            string path = null;
            string str4 = null;
            GZipFileInfo info = null;
            FileStream stream = null;
            FileStream stream2 = null;
            if ((files != null) && (files.Length > 0))
            {
                try
                {
                    result.Files = new GZipFileInfo[files.Length];
                    stream = new FileStream(lpTempFile, FileMode.Create, FileAccess.Write, FileShare.None);
                    foreach (FileInfo info2 in files)
                    {
                        string text1 = info2.DirectoryName + @"\";
                        try
                        {
                            info = new GZipFileInfo
                            {
                                Index = index
                            };
                            path = info2.FullName;
                            info.LocalPath = path;
                            str4 = path.Replace(lpBaseFolder, string.Empty).Replace(@"\", "/");
                            info.RelativePath = str4;
                            stream2 = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                            byte[] buffer = new byte[stream2.Length];
                            stream2.Read(buffer, 0, buffer.Length);
                            stream2.Close();
                            stream2 = null;
                            str2 = info2.LastWriteTimeUtc.ToString();
                            info.ModifiedDate = info2.LastWriteTimeUtc;
                            info.Length = buffer.Length;
                            string[] strArray = new string[] { index.ToString(), ",", str4, ",", str2, ",", buffer.Length.ToString(), "\n" };
                            s = string.Concat(strArray);
                            byte[] bytes = Encoding.Default.GetBytes(s);
                            stream.Write(bytes, 0, bytes.Length);
                            stream.Write(buffer, 0, buffer.Length);
                            stream.WriteByte(10);
                            info.AddedToTempFile = true;
                            result.Files[index] = info;
                            index++;
                        }
                        catch (Exception exception)
                        {
                            result.Errors = true;
                            result.Message = exception.Message;
                        }
                        finally
                        {
                            if (stream2 != null)
                            {
                                stream2.Close();
                                stream2 = null;
                            }
                        }
                        result.TempFileSize = stream.Length;
                    }
                }
                catch (Exception exception2)
                {
                    result.Errors = true;
                    result.Message = exception2.Message;
                }
                finally
                {
                    if (stream != null)
                    {
                        stream.Close();
                        stream = null;
                    }
                }
            }
            result.FileCount = index;
        }

        private static void CreateZipFile(string lpSourceFile, string lpZipFile, GZipResult result)
        {
            FileStream stream = null;
            FileStream stream2 = null;
            GZipStream stream3 = null;
            try
            {
                stream = new FileStream(lpZipFile, FileMode.Create, FileAccess.Write, FileShare.None);
                stream3 = new GZipStream(stream, CompressionMode.Compress, true);
                stream2 = new FileStream(lpSourceFile, FileMode.Open, FileAccess.Read, FileShare.Read);
                byte[] buffer = new byte[stream2.Length];
                stream2.Read(buffer, 0, buffer.Length);
                stream2.Close();
                stream2 = null;
                stream3.Write(buffer, 0, buffer.Length);
                result.ZipFileSize = stream.Length;
                result.CompressionPercent = GetCompressionPercent(result.TempFileSize, result.ZipFileSize);
            }
            catch (Exception exception)
            {
                result.Errors = true;
                result.Message = exception.Message;
            }
            finally
            {
                if (stream3 != null)
                {
                    stream3.Close();
                    stream3 = null;
                }
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }
                if (stream2 != null)
                {
                    stream2.Close();
                    stream2 = null;
                }
            }
        }

        public static GZipResult Decompress(string lpSourceFolder, string lpDestFolder, string zipFileName)
        {
            return Decompress(lpSourceFolder, lpDestFolder, zipFileName, true, true, null, null, 0x1000);
        }

        public static GZipResult Decompress(string lpSourceFolder, string lpDestFolder, string zipFileName, bool writeFiles, string addExtension)
        {
            return Decompress(lpSourceFolder, lpDestFolder, zipFileName, true, writeFiles, addExtension, null, 0x1000);
        }

        public static GZipResult Decompress(string lpSrcFolder, string lpDestFolder, string zipFileName, bool deleteTempFile, bool writeFiles, string addExtension, Hashtable htFiles, int bufferSize)
        {
            GZipResult result = new GZipResult();
            if (!lpSrcFolder.EndsWith(@"\"))
            {
                lpSrcFolder = lpSrcFolder + @"\";
            }
            if (!lpDestFolder.EndsWith(@"\"))
            {
                lpDestFolder = lpDestFolder + @"\";
            }
            string lpTempFile = lpSrcFolder + zipFileName + ".tmp";
            string lpZipFile = lpSrcFolder + zipFileName;
            result.TempFile = lpTempFile;
            result.ZipFile = lpZipFile;
            string str3 = null;
            string lpFilePath = null;
            string path = null;
            GZipFileInfo info = null;
            FileStream fs = null;
            ArrayList list = new ArrayList();
            bool flag = false;
            if (string.IsNullOrEmpty(addExtension))
            {
                addExtension = string.Empty;
            }
            else if (!addExtension.StartsWith("."))
            {
                addExtension = "." + addExtension;
            }
            try
            {
                fs = UnzipToTempFile(lpZipFile, lpTempFile, result);
                if (fs != null)
                {
                    while (fs.Position != fs.Length)
                    {
                        str3 = null;
                        while (string.IsNullOrEmpty(str3) && (fs.Position != fs.Length))
                        {
                            str3 = ReadLine(fs);
                        }
                        if (!string.IsNullOrEmpty(str3))
                        {
                            info = new GZipFileInfo();
                            if (info.ParseFileInfo(str3) && (info.Length > 0))
                            {
                                list.Add(info);
                                lpFilePath = lpDestFolder + info.RelativePath;
                                path = GetFolder(lpFilePath);
                                info.LocalPath = lpFilePath;
                                flag = false;
                                if ((htFiles == null) || htFiles.ContainsKey(info.RelativePath))
                                {
                                    info.RestoreRequested = true;
                                    flag = writeFiles;
                                }
                                if (flag)
                                {
                                    if (!Directory.Exists(path))
                                    {
                                        Directory.CreateDirectory(path);
                                    }
                                    info.Restored = WriteFile(fs, info.Length, lpFilePath + addExtension, bufferSize);
                                }
                                else
                                {
                                    fs.Position += info.Length;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                result.Errors = true;
                result.Message = exception.Message;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                    fs = null;
                }
            }
            try
            {
                if (deleteTempFile)
                {
                    File.Delete(lpTempFile);
                    result.TempFileDeleted = true;
                }
            }
            catch (Exception exception2)
            {
                result.Errors = true;
                result.Message = exception2.Message;
            }
            result.FileCount = list.Count;
            result.Files = new GZipFileInfo[list.Count];
            list.CopyTo(result.Files);
            return result;
        }

        private static int GetCompressionPercent(long tempLen, long zipLen)
        {
            double num = tempLen;
            double num2 = zipLen;
            double num3 = 100.0;
            double num4 = (num - num2) / num;
            double num5 = num4 * num3;
            return (int)num5;
        }

        private static string GetFolder(string lpFilePath)
        {
            string str = lpFilePath;
            int num = str.LastIndexOf(@"\");
            if (num != -1)
            {
                str = str.Substring(0, num + 1);
            }
            return str;
        }

        private static string ReadLine(FileStream fs)
        {
            byte[] bytes = new byte[0x1000];
            byte num = 0;
            byte num2 = 10;
            int index = 0;
            while (num != num2)
            {
                bytes[index] = (byte)fs.ReadByte();
                index++;
            }
            return Encoding.Default.GetString(bytes, 0, index - 1);
        }

        private static FileStream UnzipToTempFile(string lpZipFile, string lpTempFile, GZipResult result)
        {
            FileStream stream = null;
            GZipStream stream2 = null;
            FileStream stream3 = null;
            FileStream stream4 = null;
            byte[] buffer = new byte[0x1000];
            int count = 0;
            try
            {
                stream = new FileStream(lpZipFile, FileMode.Open, FileAccess.Read, FileShare.Read);
                result.ZipFileSize = stream.Length;
                stream3 = new FileStream(lpTempFile, FileMode.Create, FileAccess.Write, FileShare.None);
                stream2 = new GZipStream(stream, CompressionMode.Decompress, true);
                do
                {
                    count = stream2.Read(buffer, 0, 0x1000);
                    if (count != 0)
                    {
                        stream3.Write(buffer, 0, count);
                    }
                }
                while (count == 0x1000);
            }
            catch (Exception exception)
            {
                result.Errors = true;
                result.Message = exception.Message;
            }
            finally
            {
                if (stream2 != null)
                {
                    stream2.Close();
                    stream2 = null;
                }
                if (stream3 != null)
                {
                    stream3.Close();
                    stream3 = null;
                }
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }
            }
            stream4 = new FileStream(lpTempFile, FileMode.Open, FileAccess.Read, FileShare.None);
            if (stream4 != null)
            {
                result.TempFileSize = stream4.Length;
            }
            return stream4;
        }

        private static bool WriteFile(FileStream fs, int fileLength, string lpFile, int bufferSize)
        {
            bool flag = false;
            FileStream stream = null;
            if ((bufferSize == 0) || (fileLength < bufferSize))
            {
                bufferSize = fileLength;
            }
            int count = 0;
            int num2 = fileLength;
            int num3 = 0;
            try
            {
                byte[] buffer = new byte[bufferSize];
                stream = new FileStream(lpFile, FileMode.Create, FileAccess.Write, FileShare.None);
                while (num2 > 0)
                {
                    if (num2 > bufferSize)
                    {
                        num3 = bufferSize;
                    }
                    else
                    {
                        num3 = num2;
                    }
                    count = fs.Read(buffer, 0, num3);
                    num2 -= count;
                    if (count == 0)
                    {
                        break;
                    }
                    stream.Write(buffer, 0, count);
                    stream.Flush();
                }
                stream.Flush();
                stream.Close();
                stream = null;
                flag = true;
            }
            catch
            {
                flag = false;
            }
            finally
            {
                if (stream != null)
                {
                    stream.Flush();
                    stream.Close();
                    stream = null;
                }
            }
            return flag;
        }
    }

    public class GZipFileInfo
    {
        // Fields
        public bool AddedToTempFile;
        public string Folder;
        public int Index;
        public int Length;
        public string LocalPath;
        public DateTime ModifiedDate;
        public string RelativePath;
        public bool Restored;
        public bool RestoreRequested;

        // Methods
        public bool ParseFileInfo(string fileInfo)
        {
            bool flag = false;
            try
            {
                if (!string.IsNullOrEmpty(fileInfo))
                {
                    string[] strArray = fileInfo.Split(new char[] { ',' });
                    if ((strArray != null) && (strArray.Length == 4))
                    {
                        this.Index = Convert.ToInt32(strArray[0]);
                        this.RelativePath = strArray[1].Replace("/", @"\");
                        this.ModifiedDate = Convert.ToDateTime(strArray[2]);
                        this.Length = Convert.ToInt32(strArray[3]);
                        flag = true;
                    }
                }
            }
            catch
            {
                flag = false;
            }
            return flag;
        }
    }

    public class GZipResult
    {
        // Fields
        public int CompressionPercent;
        public bool Errors;
        public int FileCount;
        public GZipFileInfo[] Files;
        public string Message = "";
        public string TempFile;
        public bool TempFileDeleted;
        public long TempFileSize;
        public string ZipFile;
        public long ZipFileSize;
    }
}
